﻿
// **************************************************************************
//    Class Created by Mick Doherty (Dotnetrix) July 2010
//    http://dotnetrix.co.uk/
//
//    ...for GlassUI (an AeroGlass UI Library)
//    http://glassui.codeplex.com/
// **************************************************************************

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using GlassUI.Design;

namespace GlassUI
{
    [DefaultProperty("Checked")]
    [DefaultBindingProperty("Checked")]
    [DefaultEvent("CheckedChanged")]
    [ToolboxBitmap(typeof(System.Windows.Forms.RadioButton))]
    public class GlassRadioButton : GlassAutoSizeControlBase
    {
        public GlassRadioButton()
            : base()
        {
            this.SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable | ControlStyles.StandardClick, true);
            this.SetStyle(ControlStyles.StandardDoubleClick, false);
        }

        #region Event Declarations

        public event EventHandler CheckedChanged;

        #endregion

        #region Private Instance Variables

        private Appearance appearance = Appearance.Normal;

        private Color checkColor = Color.CornflowerBlue;

        private bool _checked;
        private bool autoCheck = true;

        private ControlState controlState = ControlState.Normal;

        #endregion

        #region Public properties

        [DefaultValue(typeof(Appearance), "Normal")]
        [GlassUIDescription("RadioButtonAppearanceDescr", "System.Windows.Forms")]
        public Appearance Appearance
        {
            get { return appearance; }
            set
            {
                appearance = value;
                if (AutoSize)
                    this.Size = this.GetPreferredSize(this.Size);
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override Image BackgroundImage
        {
            get
            {
                return base.BackgroundImage;
            }
            set
            {
                base.BackgroundImage = value;
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override ImageLayout BackgroundImageLayout
        {
            get
            {
                return base.BackgroundImageLayout;
            }
            set
            {
                base.BackgroundImageLayout = value;
            }
        }
        
        [DefaultValue(typeof(Color), "CornflowerBlue")]
        [GlassUIDescription("CheckBoxCheckColorDescription")]
        public Color CheckColor
        {
            get { return checkColor; }
            set
            {
                if (!checkColor.Equals(value))
                {
                    checkColor = value;
                    this.Invalidate();
                }
            }
        }

        [DefaultValue(false)]
        [GlassUIDescription("RadioButtonCheckedDescr", "System.Windows.Forms")]
        public bool Checked
        {
            get { return _checked; }
            set
            {
                if (_checked != value)
                {
                    _checked = value;
                    this.OnCheckedChanged(EventArgs.Empty);
                    this.Invalidate();
                }
            }
        }

        [DefaultValue(true)]
        [GlassUIDescription("RadioButtonAutoCheckDescr", "System.Windows.Forms")]
        public bool AutoCheck
        {
            get { return autoCheck; }
            set { autoCheck = value; }
        }

        internal ControlState ControlState
        {
            get { return controlState; }
            set
            {
                if (controlState != value)
                {
                    controlState = value;
                    this.Invalidate();
                }
            }
        }

        #endregion

        #region Overridden Properties

        protected override Size DefaultSize
        {
            get
            {
                return new Size(104, 24);
            }
        }

        #endregion

        #region Overridden Methods

        public override Size GetPreferredSize(Size proposedSize)
        {
            int h = this.Appearance == Appearance.Button ? 0 : this.FontHeight;

            Size checkSize = new Size(h, h);
            Size availableTextSize = Size.Empty;
            Size textSize = Size.Empty;

            Rectangle contentBounds = Rectangle.Empty;
            TextFormatFlags format = TextFormatFlags.TextBoxControl | TextFormatFlags.SingleLine | TextFormatFlags.NoPadding;

            availableTextSize = new Size(proposedSize.Width - checkSize.Width, proposedSize.Height);

            if (this.Text.Length > 0)
            {
                using (Graphics graphics = this.CreateGraphics())
                {
                    textSize = GlassUtilities.MeasureThemedText(graphics, this.Text, this.Font, availableTextSize, format, 8);
                }
            }

            contentBounds.Width = checkSize.Width + textSize.Width + 4;
            contentBounds.Height = Math.Max(checkSize.Height, textSize.Height);

            contentBounds.Width += Padding.Horizontal;
            contentBounds.Height += Padding.Vertical;

            return contentBounds.Size;
        }

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            base.OnPaintBackground(pevent);

            pevent.Graphics.SmoothingMode = SmoothingMode.HighQuality;

            int h = this.Appearance == Appearance.Button ? 0 : this.FontHeight;

            Rectangle r = this.Appearance == Appearance.Button ? this.ClientRectangle : new Rectangle(2, (this.Height / 2) - (h / 2), h, h);

            if (this.BackColor.A < 255)
                DrawParentBackground(pevent.Graphics);

            if (this.Appearance == Appearance.Button)
            {
                pevent.Graphics.CompositingQuality = CompositingQuality.HighQuality;
                using (GraphicsPath path = GlassUtilities.RoundedRectangle(r, this.CornerRadius, this.RoundedCorners))
                {
                    pevent.Graphics.SetClip(path, CombineMode.Replace);
                    ControlState state = this.ControlState;
                    if (this.Checked)
                        state = ControlState.Pressed;
                    GlassUtilities.DrawGlowGradient(pevent.Graphics, r, this.Checked ? this.CheckColor : this.BackColor, this.GlowColor, state);
                    pevent.Graphics.ResetClip();
                    GlassUtilities.DrawRoundedBorder(pevent.Graphics, r, this.CornerRadius, this.RoundedCorners, state == ControlState.Pressed ? this.GlowColor : Color.Empty);
                }
            }
            else
            {
                using (LinearGradientBrush brush = new LinearGradientBrush(r, Color.Empty, this.BackColor, LinearGradientMode.ForwardDiagonal))
                {
                    using (Pen pen = new Pen(brush))
                    {
                        Color darkColor = Color.FromArgb(192, Color.Black);

                        /* Draw Glow */
                        if (this.controlState == ControlState.Hot)
                        {
                            Rectangle glowBounds = this.ClientRectangle;
                            using (PathGradientBrush glowBrush = new PathGradientBrush(GlassUtilities.RoundedRectangle(glowBounds, 2)))
                            {
                                glowBrush.CenterColor = this.GlowColor;
                                glowBrush.SurroundColors = new Color[] { Color.Transparent };
                                pevent.Graphics.FillRectangle(glowBrush, glowBounds);
                            }
                        }

                        /* Draw Dark Border */
                        pen.Color = darkColor;
                        pevent.Graphics.DrawEllipse(pen, r);

                        /* Draw Light Border */
                        r.Inflate(-1, -1);
                        Color lightColor = Color.FromArgb(192, Color.White);
                        pen.Color = this.ControlState == ControlState.Hot ? this.GlowColor : lightColor;
                        pevent.Graphics.DrawEllipse(pen, r);

                        r.Inflate(-1, -1);

                        if (this.Checked)
                            GlassUtilities.DrawStone(pevent.Graphics, r, checkColor);
                        else
                        {
                            /* Draw Gradient Fill */
                            brush.LinearColors = new Color[] { darkColor, lightColor };
                            pevent.Graphics.FillEllipse(brush, r);
                        }

                    }
                }
            }

            //Draw Text
            DrawText(pevent.Graphics);

            //Draw Focus
            if (this.Focused && this.ShowFocusCues)
                ControlPaint.DrawFocusRectangle(pevent.Graphics, this.ClientRectangle, this.ForeColor, this.BackColor);

        }

        protected override void OnClick(EventArgs e)
        {
            if (this.AutoCheck)
                this.Checked = true;
            base.OnClick(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            if (e.KeyCode == Keys.Space)
            {
                this.ControlState = ControlState.Pressed;
            }
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e);
            if (e.KeyCode == Keys.Space)
            {
                if (this.ControlState == ControlState.Pressed)
                {
                    this.PerformClick();
                }
                this.ControlState = ControlState.Focused;
            }
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            this.ControlState = ControlState.Hot;
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            this.ControlState = ControlState.Normal;
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (e.Button == MouseButtons.Left)
            {
                this.Focus();
                this.ControlState = ControlState.Pressed;
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            this.ControlState = ControlState.Focused;
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (new Rectangle(Point.Empty, this.Size).Contains(e.X, e.Y) && e.Button == MouseButtons.Left)
                this.ControlState = ControlState.Pressed;
            else
            {
                this.ControlState = ControlState.Hot;
            }
        }

        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
            this.ControlState = ControlState.Focused;
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
            this.ControlState = ControlState.Normal;
        }

        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);
            if (this.Enabled)
                this.ControlState = ControlState.Normal;
            else
                this.ControlState = ControlState.Disabled;
        }

        protected override void Select(bool directed, bool forward)
        {
            base.Select(directed, forward);
            this.OnClick(EventArgs.Empty);
        }

        public void PerformClick()
        {
            if (this.CanSelect)
                this.OnClick(EventArgs.Empty);
        }

        public override string ToString()
        {
            String val = base.ToString();
            return val + ", Checked: " + this.Checked.ToString();
        }

        #endregion

        protected virtual void OnCheckedChanged(EventArgs eventArgs)
        {
            if (this.Checked)
            {
                if (this.Parent == null)
                    return;
                foreach (Control child in this.Parent.Controls)
                {
                    if (child != this)
                        UnCheckChild(child as GlassRadioButton);
                }
            }
            if (this.CheckedChanged != null)
                this.CheckedChanged(this, eventArgs);
        }

        private static void UnCheckChild(GlassRadioButton child)
        {
            if (child != null)
                child.Checked = false;
        }

        private void DrawText(Graphics g)
        {
            Color textColor = this.ForeColor;

            bool isButton = this.Appearance == Appearance.Button;
            int h = isButton ? 0 : this.FontHeight;

            Rectangle bounds = Rectangle.FromLTRB(isButton ? 0 : h + 4, 0, this.Width, this.Height);

            if (!this.Enabled)
                textColor = SystemColors.GrayText;

            TextFormatFlags format = TextFormatFlags.EndEllipsis | TextFormatFlags.NoPadding | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter;
            if (!this.ShowKeyboardCues)
                format |= TextFormatFlags.HidePrefix;

            GlassUtilities.DrawThemedText(g, this.Text, this.Font, bounds, textColor, format, 8);

        }

    }
}

